package com.jason.reflect;

import com.jason.reflect.bean.Person;
import com.jason.reflect.bean.Person2;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;

/**
 * 反射类的方法
 * @Author: Jason
 * @Date: 16/4/7
 * @Time: 23:08
 */
public class ReflectTest03 {


    // 反射类的方法 public void aa1()
    @Test
    public void test1() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {

        Class clazz = Class.forName("com.jason.reflect.bean.Person");
        Method method = clazz.getMethod("aa1", null);
        Person p = (Person) clazz.newInstance();
        method.invoke(p, null);

    }

    // 通过配置文件来设置 创建对象
    @Test
    public void test2() throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException {
        Properties p = new Properties();
        InputStream in = Person.class.getResourceAsStream("conf.properties");
        p.load(in);

        // 获取需要加载的文件名
        String claName = p.getProperty("name");
        System.out.println("claName-------"+claName);

//         返回的cls是Person.class这个字符串所指的类的字节码
        Class cls = Class.forName(claName);
//        Class cls = Class.forName("com.jason.reflect.bean.Person2");
        System.out.println("cls is ----" + claName);

        Person2 o = (Person2) cls.newInstance();
        System.out.println("o------>" + o);



    }

    /**
     * 测试通过反射方法来调用
     * 要从一个类的字节码中获取一个方法的反射。 - Method
     *
     * Step1: 必须要获取此类的字节码  Class.forName(...);
     *
     * Step2: 必须要先实例此字节码所表示的类 : newInstance();
     *
     * Step3: 从字节码中,分析出setName这个方法Method - cls.getMethod("方法名",参数是什么 ... 参数);
     *
     * Step4: Method类的方法invoke用于执行某个对象的方法且可以设置参数
     *        method.invoke(具体的对象,参数实例...参数)
     *
     * Step5: 调用私有的成员变量也可以设置值。
     *        要从字节码中获取这个成员变量的字节码对象。 File
     *
     * Step6: 通过调用filed的set方法可以设置新的数据值
     */
    @Test
    public void testMethod() throws Exception {

        Class<?> cls = Class.forName("com.jason.reflect.bean.Person3");
        Constructor<?> con = cls.getDeclaredConstructor(String.class, String.class);
        con.setAccessible(true);
        Object person = con.newInstance("Jason", "北京");

        Method method = cls.getDeclaredMethod("setName", String.class);
        method.setAccessible(true);
        method.invoke(person, "Rose");

        System.out.println("Person修改以后: " + person);

        Field field = cls.getDeclaredField("name");
        field.setAccessible(true);
        field.set(person, "Tom");

        System.out.println("Person最后值: " + person);


    }

}
